package io.gitee.kotle.android.library.websocket

import androidx.annotation.RequiresPermission
import io.gitee.kotle.android.utils.NetworkStatusUtil
import io.gitee.kotle.android.utils.log
import io.gitee.kotle.android.utils.startNetWorkObServe
import io.gitee.kotle.android.utils.stopNetWorkObServe
import kotlinx.coroutines.*


/**
 *
 * 描述：支持断线自动重连
 *
 * @author jiale.wei
 *
 * 创建时间：2022/8/10 16:08
 *
 */

open class WebSocketHelper(
    @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
    val webSocket: IWebSocket,
    val wsUrl: String,
    val onMessage: (String) -> Unit
) {
    companion object {
        const val START_DELAY_RECONNECT_TIME = -60_000L
        const val ADD_DELAY_RECONNECT_TIME = 60_000L
    }

    private var isConnect = false
    private val scope = MainScope()
    private var delayReConnectJob: Job? = null
    private val waitSendMsgList = mutableListOf<String>()

    /**
     * 重连时间从一分钟开始递增
     */
    private var currentDelayTime = START_DELAY_RECONNECT_TIME

    private val webSocketListener = object : IWebSocket.Listener {
        override fun onConnectStatus(status: WebSocketStatus) {
            super.onConnectStatus(status)
            when (status) {
                is WebSocketStatus.ConnectFail -> {
                    isConnect = false
                    log { "----->websocket连接失败(${status.error})" }
                    startReconnect()
                }
                WebSocketStatus.ConnectSuccess -> {
                    isConnect = true
                    log { "----->websocket连接成功" }
                    //处理发送失败的消息
                    if (waitSendMsgList.isNotEmpty()) {
                        val newList = waitSendMsgList.toList()
                        waitSendMsgList.clear()
                        newList.forEach {
                            sendMessage(it, true)
                        }
                    }
                    currentDelayTime = START_DELAY_RECONNECT_TIME
                    cancelReconnect()
                }
            }
        }

        override fun onMessage(data: String) {
            super.onMessage(data)
            onMessage.invoke(data)
        }
    }

    private val networkListener = object : NetworkStatusUtil.StatusListener {
        override fun onNetWorkChange(status: Int) {
            if (NetworkStatusUtil.isNetWorkAvailable) {
                currentDelayTime = START_DELAY_RECONNECT_TIME
                cancelReconnect()
            }
            startReconnect()
        }
    }

    init {
        startNetWorkObServe(networkListener)
        webSocket.addListener(webSocketListener)
        startConnect()
    }

    /**
     * 开始重连
     */
    private fun startReconnect() {
        //如果已经连接
        if (isConnect) {
            return
        }
        //网络不可用
        if (!NetworkStatusUtil.isNetWorkAvailable) {
            return
        }
        //已经有重连任务
        if (delayReConnectJob?.isActive == true) {
            return
        }
        delayReConnectJob = scope.launch {
            currentDelayTime += ADD_DELAY_RECONNECT_TIME
            log { "----->${currentDelayTime}ms后，开始连接websocket（${wsUrl}）" }
            if (currentDelayTime > 0) {
                delay(currentDelayTime)
            }
            startConnect()
        }
    }

    private fun startConnect() {
        //如果已经连接
        if (isConnect) {
            return
        }
        //网络不可用
        if (!NetworkStatusUtil.isNetWorkAvailable) {
            return
        }
        log { "----->开始连接websocket（${wsUrl}）" }
        webSocket.connect(wsUrl)
    }

    /**
     * 取消重连
     */
    private fun cancelReconnect() {
        if (delayReConnectJob?.isActive == true) {
            delayReConnectJob?.cancel()
        }
        delayReConnectJob = null
    }

    /**
     * 发送消息
     * [saveQueueWhenSendFail] 发送失败是否保存到列表，连接后自动发送
     */
    fun sendMessage(msg: String?, saveQueueWhenSendFail: Boolean = true): Boolean {
        msg ?: return false
        if (!isConnect) {
            if (saveQueueWhenSendFail) {
                waitSendMsgList.add(msg)
            }
            startReconnect()
            log { "----->未连接，消息发送失败（$msg）" }
            return false
        }
        val success = webSocket.send(msg)
        if (!success && saveQueueWhenSendFail) {
            waitSendMsgList.add(msg)
        }
        log { "----->消息发送$success ($msg)" }
        return success
    }


    /**
     * 清除未发生的消息
     * [block]返回true则会移除消息
     */
    fun clearWaitSendMessage(block: (String) -> Boolean = { true }) {
        waitSendMsgList.toList().forEach {
            if (block.invoke(it)) {
                waitSendMsgList.remove(it)
            }
        }
    }


    /**
     * 销毁
     */
    fun destroy() {
        webSocket.disConnect()
        webSocket.removeListener(webSocketListener)
        stopNetWorkObServe(networkListener)
        cancelReconnect()
        scope.cancel()
        log { "----->websocket destroy" }
    }
}